package com.wechatapp.mengyao.poetry.core;

import com.wechatapp.mengyao.poetry.dto.LoginRequestDTO;
import com.wechatapp.mengyao.poetry.dto.WeChatInfo;
import com.wechatapp.mengyao.poetry.exception.InvalidTokenException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
import java.util.Map;

/**
 * @author yanghuaxu
 * @date 2025/5/20 20:16
 */
@Component
@Slf4j
public class WeChatHelper {

    @Value("${wechat.appid}")
    private String appid;

    @Value("${wechat.secret}")
    private String secret;

    @Value("${wechat.jscode2session-url}")
    private String jscode2sessionUrl;

    public WeChatInfo parseWeChatInfo(LoginRequestDTO login) {
        try {
            Map<String, Object> sessionKeyMap = getSessionKey(login.getCode());
            if (sessionKeyMap.containsKey("errcode")) {
                throw new RuntimeException("微信接口错误: " + sessionKeyMap.get("errmsg"));
            }
            String sessionKey = sessionKeyMap.get("session_key").toString();
            String openid = sessionKeyMap.get("openid").toString();
            // 2. 解密用户信息
            Map<String, Object> userInfo = decryptData(
                    login.getEncryptedData(),
                    login.getIv(),
                    sessionKey
            );
            // 3. 获取 unionid（如果存在）
            String unionId = userInfo.getOrDefault("unionId", "").toString();
            return new WeChatInfo(openid, unionId);
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
            log.error("解密失败-数据块长度异常，错误：{}", e.getMessage());
            throw new InvalidTokenException("加密数据格式错误");
        } catch (BadPaddingException e) {
            e.printStackTrace();
            log.error("解密失败-密钥不匹配，错误：{}", e.getMessage());
            throw new InvalidTokenException("会话密钥已失效");
        } catch (InvalidAlgorithmParameterException | InvalidKeyException e) {
            e.printStackTrace();
            log.error("解密失败-参数异常，错误类型：{}", e.getClass().getSimpleName());
            throw new InvalidTokenException("解密参数异常");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            String errorMsg = String.format("解密失败-不支持的加密算法配置：%s，请检查系统环境", "AES/CBC/PKCS5Padding");
            log.error(errorMsg);
            throw new InvalidTokenException("系统加密配置错误");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            String errorMsg = String.format("解密失败-填充模式不可用：%s，建议检查填充方案", "PKCS5Padding");
            log.error(errorMsg);
            throw new InvalidTokenException("数据填充格式错误");
        } catch (Exception e) {
            e.printStackTrace();
            throw new InvalidTokenException("未知错误");
        }
    }

    // 获取 session_key 和 openid
    public Map<String, Object> getSessionKey(String code) throws Exception {
        String url = jscode2sessionUrl + "?appid=" + appid
                + "&secret=" + secret + "&js_code=" + code
                + "&grant_type=authorization_code";
        log.info("开始请求：{}", url);
        CloseableHttpClient client = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response = client.execute(httpGet);

        String result = EntityUtils.toString(response.getEntity());
        log.info("返回结果为：{}", result);
        return JsonUtils.parseMap(result);
    }

    // 解密用户数据
    public Map<String, Object> decryptData(String encryptedData, String iv, String sessionKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchProviderException {

        byte[] data = Base64.getDecoder().decode(encryptedData);
        byte[] key = Base64.getDecoder().decode(sessionKey);
        byte[] ivBytes = Base64.getDecoder().decode(iv);
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding","BC");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

        byte[] decrypted = cipher.doFinal(data);
        String result = new String(decrypted, StandardCharsets.UTF_8);
        return JsonUtils.parseMap(result);
    }
}
